#!/usr/bin/env python

from twisted.internet import reactor, defer, stdio
from twisted.internet.protocol import _InstanceFactory
from twisted.protocols import amp
from tankserver import default_port
from connect import ConnectDialog
import commands
from twisted.protocols import basic
from twisted.internet.task import LoopingCall
import time

default_host = "10.10.0.1"

class ChatClientProtocol(amp.AMP):

    @commands.Send.responder
    def send(self, message, sender):
        """Send message to this client from sender"""
        chatclient.receive_chat_message(message, sender)
        return {}

    @commands.AddUser.responder
    def add_user(self, user):
        print "client add_user called,",user," has joined"		
        return {}

    @commands.DelUser.responder
    def del_user(self, user):
        print "user ",user," has left"		
        return {}

    @commands.ReceiveMap.responder
    def receive_map(self, map):
        print "client receive_map called=",map
        return {}


class ChatClientFactory(_InstanceFactory):
    protocol = ChatClientProtocol

    def __init__(self, reactor, instance, deferred):
        _InstanceFactory.__init__(self, reactor, instance, deferred)

    def __repr__(self):
        return "<ChatClient factory: %r>" % (self.instance, )

class ChatClient(object):
    def __init__(self):
        self.protocol = None
        self.host = None
        self.port = None
        self.username = None
        self.password = None
        self.serverConnected = 1 
        self.bt=0
        self.et=0
        self.diff=0
        self.counter=0

    def connect_to_server(self, host, port, username, password):
        self.host = host
        self.port = port
        self.username = username
        self.password = password
        deferred = defer.Deferred()
        if self.protocol is not None:
            self.protocol.transport.loseConnection()
        factory = ChatClientFactory(reactor, ChatClientProtocol(), deferred)
        connector = reactor.connectTCP(self.host, self.port, factory)
        deferred.addCallback(self.connected_to_server)
        deferred.addErrback(self.failure)
        return deferred

    def connected_to_server(self, protocol):
        self.protocol = protocol
        deferred = protocol.callRemote(commands.Login, username=self.username, 
          password=self.password)
        deferred.addCallback(self.cb_login)
        deferred.addErrback(self.eb_login)

    def cb_login(self, response):
        self.serverConnected=1
        print "client connect_to_server completed without error, login successful as %s" % chatclient.username
        print "self.serverConnected=",self.serverConnected

    def eb_login(self, error):
		print "login unsuccessful as %s -- not logged in" % chatclient.username


    def failure(self, error):
           print "Could not connect to %s:%s\n%s" % (self.host, self.port, error)

    def stop(self, unused):
        reactor.stop()

    def get_update(self):
        text = "hello"
        self.bt=time.time()
#        print "in get_update serverConnected=",self.serverConnected
        if self.serverConnected==1 and text and self.protocol is not None:
            deferred = self.protocol.callRemote(commands.GetUpdate,message=text)
            deferred.addCallback(self.print_update)
            deferred.addErrback(self.failed_update)
#        return deferred

    def print_update(self,response):
        self.et=time.time()
        self.diff=self.diff+(self.et-self.bt)
	self.counter=self.counter+1
	if (self.counter>200):
           print "average latency =",(self.diff/200)*1000,"ms"
           reactor.stop()
#        print "response=",response
        return {}

    def failed_update(self,response):
        raise commands.LoginError("Incorrect username or password")

    def speak(self):
        text = "hello"
        if text and self.protocol is not None:
           deferred = self.protocol.callRemote(commands.SendToAll, 
                message=text)
        deferred.addErrback(self.failure)

    def cb_user_list_select(self, selection, model, path, is_selected, unused):
        index = path[0]
        row = self.user_store[index, 0]
        name = row[0]
        if is_selected:
            self.selected_names.remove(name)
        else:
            self.selected_names.add(name)
        return True

    def update_user_store(self, usernames):
        sorted_usernames = sorted(usernames)
        length = len(self.user_store)
        for ii, username in enumerate(sorted_usernames):
            if ii < length:
                self.user_store[ii, 0] = (username,)
            else:
                self.user_store.append((username,))
        length = len(sorted_usernames)
        while len(self.user_store) > length:
            del self.user_store[length]

    def receive_chat_message(self, message, sender):
		print sender,":",message.strip(),"\n"

    def receive_update(self, message):
		print "update=",message.strip(),"\n"

class WebCheckerCommandProtocol(basic.LineReceiver):
    delimiter = '\n' # unix terminal style newlines. remove this line
                     # for use with Telnet

    def connectionMade(self):
        self.sendLine("Tank client console.  Type 'help' for help.")

    def lineReceived(self, line):
        # Ignore blank lines
        if not line: return

        # Parse the command
        commandParts = line.split()
        command = commandParts[0].lower()
        args = commandParts[1:]

        # Dispatch the command to the appropriate method.  Note that all you
        # need to do to implement a new command is add another do_* method.
        try:
            method = getattr(self, 'do_' + command)
        except AttributeError, e:
            self.sendLine('Error: no such command.')
        else:
            try:
                method(*args)
            except Exception, e:
                self.sendLine('Error: ' + str(e))

    def do_help(self, command=None):
        """help [command]: List commands, or show help on the given command"""
        if command:
            self.sendLine(getattr(self, 'do_' + command).__doc__)
        else:
            commands = [cmd[3:] for cmd in dir(self) if cmd.startswith('do_')]
            self.sendLine("Valid commands: " +" ".join(commands))

    def do_connecta(self):
        chatclient.connect_to_server(port=65432,host=default_host,username="a",password="a");

    def do_connectb(self):
        chatclient.connect_to_server(port=65432,host=default_host,username="b",password="b");
	
    def do_startwork(self):
        print "asking for updates at 10hz"
        lc=LoopingCall(chatclient.get_update)
        lc.start(0.1)

    def do_work(self):
        chatclient.get_update()

    def do_speak(self):
        chatclient.speak()





if __name__ == "__main__":
    # XXX Protocol can't find its factory to find the ChatClient, so put it 
    # in a global for now.
    chatclient = ChatClient()
#    lc=LoopingCall(chatclient.get_update())
#    lc.start(0.1)
    p1=WebCheckerCommandProtocol()
    stdio.StandardIO(p1)
    reactor.run()
